package mt521.cam.ac.uk;

import java.io.File;

public class Encode {

    private static float sampleRate = 32000f;   //sample rate, must be (power of 2)*1000
    private static int msecs = 64;            //duration of each tone, must be power of 2
    private static int chunkSize = msecs*((int)sampleRate)/1000;    //the size of one block of encoded data in bytes
    private static int spacing = 30;
    
    public static float getSampleRate() {
        return sampleRate;
    }
    public static int getMsecs() {
        return msecs;
    }
    public static int getChunkSize() {
        return chunkSize;
    }
    public static int getSpacing() {
        return spacing;
    }
    
    public static void run(String[] args) {
        if (args.length>1) {
            System.err.println("Use single string of the form 'freq1,freq2,freq3a-freq3b-freq3c,freq4'");
            System.exit(0);
        }
        String[] data = args[0].split(",");
        File dest = new File("sound1.wav");
        int freqNum = data.length;
        if (freqNum>1) {
            byte[] wave = null;
            byte[][] sineWaves = new byte[freqNum][];
            for (int i=0; i<freqNum; i++) {
                wave = makeTone(data[i]);
                sineWaves[i] = wave;
            }
            Output.saveMult(sineWaves,dest,msecs);
        }
        else {
            byte[] wave = makeTone(data[0]);
            Output.save(wave,dest,msecs);
        }
    }
    
    //decide if single tone or chord
    public static byte[] makeTone(String data) {
        byte[] toReturn;
        try {
            int freq = Integer.parseInt(data);
            toReturn= buffer(freq);
        }
        catch (NumberFormatException e) {
            String[] freqs = data.split("-");
            return bufferChord(freqs);
        }
        return toReturn;
    }
    
    //single tone
    public static byte[] buffer(int freq) {
        byte[] sineWave = new byte[((int)sampleRate)*msecs/1000];
        float freqRatio = sampleRate/freq; //allow for mismatch in sample rate and frequency (both measured in Hz)
        for (int i=0; i<sineWave.length; i++) {
            double angle = i/freqRatio * 2.0 * Math.PI; //radians, multiply by 2PI as going to be used in sine wave
            sineWave[i] = (byte)(Math.sin(angle) * 127.0);
            //sine of an angle gives ~1->1, we want a number in the range ~128->127 (8 bits), so multiply by
            //127 to use all byte values.
        }
        return sineWave;
    }

    //multiple tones on top of each other
    public static byte[] bufferChord(String[] freqs) {
        byte[] sineWave = new byte[(int)sampleRate*msecs/1000];
        for (int n=0; n<freqs.length; n++) {
            float freqRatio = sampleRate/Integer.parseInt(freqs[n]);
            for (int i=0; i<sineWave.length; i++) {
                double angle = i/freqRatio * 2.0 * Math.PI;
                sineWave[i] += (byte)(Math.sin(angle) * (127.0/freqs.length));
            }
        }
        return sineWave;
    }
    
    public static void encode(byte[] data) {
        int seqLen = data.length; 
        byte[][] complete = new byte[seqLen][];
        byte[] wave = null;
        File dest = new File("sound1.wav");
        int msecs = Encode.getMsecs();
        int freq;
        
        for (int i=0; i<seqLen; i++) {
            freq = data[i]>0 ? (int)data[i] : ((int)data[i])+256; //make all frequencies positive
            wave = Encode.buffer((freq*spacing)+300);
            complete[i] = wave;
        }
        
        Output.saveMult(complete,dest,msecs);
    }
    
}
